package com.md.api.service.impl;

import cn.hutool.core.date.DateUtil;
import com.aliyun.oss.model.StorageClass;
import com.md.api.common.exception.BusinessException;
import com.md.api.common.utils.*;
import com.md.api.dao.*;
import com.md.api.entity.*;
import com.md.api.entity.dto.ProductBuyDto;
import com.md.api.entity.dto.ShopCartBuyDto;
import com.md.api.entity.dto.VipBuyDto;
import com.md.api.entity.enums.*;
import com.md.api.entity.util.PayResult;
import com.md.api.service.PayService;
import com.md.api.service.UserSevice;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Author liujie
 * @ClassName ProductServiceImpl
 **/

@Slf4j
@Service
public class PayServiceImpl implements PayService {
    @Resource
    private UserSevice userSevice;
    @Resource
    private UserFtpMapper ftpMapper;
    @Resource
    TbOrderVirtuallyMapper orderVirtuallyMapper;
    @Resource
    PdSkuMapper pdSkuMapper;
    @Resource
    UserVipMapper userVipMapper;
    @Resource
    PdAttributeValueMapper attributeValueMapper;
    @Resource
    RedisUtil redisUtil;
    @Resource
    RedissonClient redisson;
    @Resource
    TokenUtil tokenUtil;
    @Resource
    VipPropertiesMapper vipPropertiesMapper;
    @Resource
    ReceivingAddrInfoMapper addrInfoMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    TbOrderMapper orderMapper;
    @Resource
    TbOrdeDetailMapper ordeDetailMapper;
    @Resource
    ShoppingCartMapper cartMapper;
    @Resource
    PhotoInfoMapper photoMapper;
    @Resource
    PictureInfoMapper pictureMapper;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    @Override
    public HttpResult productBuy(HttpServletRequest request, ProductBuyDto buyDto)  {
        try {
            String userId = tokenUtil.getUserId(request);
            String language = request.getHeader("language");
            PdSku sku = pdSkuMapper.getBySkuId(buyDto.getSkuId());
            if (sku.getSaleStatus()== SaleStatus.SELL_OUT.value()){
                return HttpResult.fail("該商品已售罄！");
            }
            BigDecimal singlePrice = new BigDecimal(null!=sku.getDiscountPrice()?sku.getDiscountPrice():sku.getOrginPrice());
            BigDecimal numCount = new BigDecimal(buyDto.getNumCount());
            //余额支付先判断余额是否充足
            if (buyDto.getPayType() == PayType.BALANCE.value()) {
                UserInfo user = userMapper.getByUserId(userId);
                BigDecimal balance = new BigDecimal(user.getBalance());
                if (balance.subtract(singlePrice.multiply(numCount)).doubleValue()<0){
                    if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                        return HttpResult.fail("Your balance is insufficient, please recharge");
                    }
                    return HttpResult.fail("您的餘額不足，請確認！");
                }
            }
            //实物产品先判断库存量
            if(ProductType.GOODS.value()== sku.getType()) {
                String key = "sku_" + buyDto.getSkuId();
                if (redisUtil.hasKey(key)) {//没有初始化数量的产品，不限制购买数量
                    String lock_key = "sku_lock_" + buyDto.getSkuId();
                    RLock lock = redisson.getLock(lock_key);
                    //try catch 设计是为了防止在执行业务的时候出现异常导致redis锁一直无法释放
                    try {
                        lock.lock();
                        int count = Integer.parseInt(redisUtil.get(key).toString());
                        if (count == 0) {
                            if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                                return HttpResult.fail("The product is sold out");
                            }
                            return HttpResult.fail("該商品已售罄！");
                        }
                        if (buyDto.getNumCount() > count) {
                            if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                                return HttpResult.fail("The quantity of this product is less than"+ buyDto.getNumCount() + "pieces！");
                            }
                            return HttpResult.fail("該商品數量不足" + buyDto.getNumCount() + "件！");
                        }
                    } catch (Throwable e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            }
            //初始订单
            String code = CodeUtil.verifyCode(6);
            String today = DateUtil.format(new Date(), "yyyyMMdd");
            Double totalMoney = singlePrice.multiply(numCount).doubleValue();
            String orderNo = "sn".concat(today).concat(code);
            String agent = request.getHeader("agent");
            if (StringUtils.isNotEmpty(agent)&&agent.equals("app")){
                orderNo = "sp".concat(today).concat(code);
            }
            TbOrder order = new TbOrder();
            order.setOrderNo(orderNo);
            order.setUserId(userId);
            order.setPayType(buyDto.getPayType());
            order.setOrderType(OrderType.PRODUCT.value());
            order.setPayStatus(PayStatus.PAYING.value());
            order.setActualPay(totalMoney);
            order.setTotalPay(totalMoney);
            //回填订单收件人信息
            if (StringUtils.isNotEmpty(buyDto.getReceivingAddrId())) {
                ReceivingAddrInfo addrInfo = addrInfoMapper.getByReceivingAddrId(buyDto.getReceivingAddrId());
                order.setReceiverAddress(addrInfo.getReceivingAddress());
                order.setReceiverMobile(addrInfo.getContactPhone());
                order.setReceiver(addrInfo.getContact());
            }

            TbOrderDetail detail = new TbOrderDetail();
            detail.setOrderNo(orderNo);
            detail.setSkuId(buyDto.getSkuId());
            detail.setSkuName(sku.getSkuName());
            detail.setSkuSpecs(sku.getSkuSpecs());
            detail.setImage(sku.getSkuImgUrl());
            detail.setDeliveryWay(buyDto.getDeliveryWay());
            detail.setPrice(null != sku.getDiscountPrice() ? sku.getDiscountPrice() : sku.getOrginPrice());
            detail.setNumCount(buyDto.getNumCount());

            //余额支付直接扣款
            if (buyDto.getPayType() == PayType.BALANCE.value()) {
                detail.setIsConfirm(1);
                UserInfo user = userMapper.getByUserId(userId);
                BigDecimal num1 = new BigDecimal(user.getBalance());
                BigDecimal num2 = new BigDecimal(null != sku.getDiscountPrice() ? sku.getDiscountPrice() : sku.getOrginPrice());
                user.setBalance(num1.subtract(num2).doubleValue());
                userMapper.updateBalance(user);
                //主动触发回调
                order.setPayTime(new Date());
                order.setCloseTime(new Date());
                order.setEndTime(new Date());
                order.setPayStatus(PayStatus.COMPLETED.value());
                PdSku dbSku = pdSkuMapper.getBySkuId(detail.getSkuId());
                String key = "sku_" + detail.getSkuId();
                //实物产品修改产品库存数
                if (redisUtil.hasKey(key) && ProductType.GOODS.value() == dbSku.getType()) {
                    String lock_key = "sku_lock_" + detail.getSkuId();
                    RLock lock = redisson.getLock(lock_key);
                    //try catch 设计是为了防止在执行业务的时候出现异常导致redis锁一直无法释放
                    try {
                        lock.lock();
                        int count = Integer.parseInt(redisUtil.get(key).toString());
                        int stockCount = count - detail.getNumCount();
                        int saleCount = dbSku.getSaleStockCount() + detail.getNumCount();
                        if (saleCount >= dbSku.getLockStockCount() || 0 >= stockCount) {
                            dbSku.setSaleStatus(SaleStatus.SELL_OUT.value());
                        }
                        dbSku.setSaleStockCount(saleCount);
                        redisUtil.set(key, stockCount);
                        dbSku.setStockCount(stockCount);
                        pdSkuMapper.updateStockCount(dbSku);
                    } catch (Throwable e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
                //AI、人脸次数
                if (ProductType.AI_TIMES.value() == dbSku.getType()||ProductType.FACE_TIMES.value() == dbSku.getType()) {
                    List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                    if (!CollectionUtils.isEmpty(attributeValues)) {
                        String value = attributeValues.get(0).getAttributeValue();
                        Integer times = Integer.valueOf(value.replaceAll("[^0-9]", "")) * detail.getNumCount();
                        TbOrderVirtually orderStorage = new TbOrderVirtually();
                        orderStorage.setUserId(order.getUserId());
                        orderStorage.setOrderNo(orderNo);
                        orderStorage.setVirtuallyType(ProductType.AI_TIMES.value());
                        if (ProductType.FACE_TIMES.value()==dbSku.getType()) {
                            orderStorage.setVirtuallyType(ProductType.FACE_TIMES.value());
                        }
                        orderStorage.setNumCount(detail.getNumCount());
                        orderStorage.setSkuId(detail.getSkuId());
                        orderStorage.setStorageOrTimes(times);
                        orderStorage.setPurchaseTime(new Date());
                        orderStorage.setEffectiveTime(new Date());
                        orderVirtuallyMapper.insert(orderStorage);
                    }
                }

                //储存空间
                if (ProductType.STORAGE.value() == dbSku.getType()) {
                    List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                    if (!CollectionUtils.isEmpty(attributeValues)) {
                        String value = attributeValues.get(0).getAttributeValue();
                        Integer storage = Integer.valueOf(value.replaceAll("[^0-9]", "")) * detail.getNumCount();
                        TbOrderVirtually orderStorage = new TbOrderVirtually();
                        orderStorage.setUserId(order.getUserId());
                        orderStorage.setOrderNo(orderNo);
                        orderStorage.setNumCount(detail.getNumCount());
                        orderStorage.setSkuId(detail.getSkuId());
                        orderStorage.setStorageOrTimes(storage);
                        orderStorage.setVirtuallyType(ProductType.STORAGE.value());
                        orderStorage.setPurchaseTime(new Date());
                        orderStorage.setEffectiveTime(new Date());
                        if (value.contains("GB/年")) {
                            orderStorage.setDateType(1);
                            orderStorage.setExpiredTime(DateUtils.add(new Date(), Calendar.YEAR, 1));
                        } else if (value.contains("GB/月")) {
                            orderStorage.setDateType(2);
                            orderStorage.setExpiredTime(DateUtils.add(new Date(), Calendar.MONTH, 1));
                        }
                        orderVirtuallyMapper.insert(orderStorage);
                    }
                }
            }
            orderMapper.initOrder(order);
            ordeDetailMapper.insert(detail);
            return new HttpResult(orderNo);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    @Override
    public HttpResult shopCartBuy(HttpServletRequest request, ShopCartBuyDto buyDto) {
        try {

            String language = request.getHeader("language");
            String userId = tokenUtil.getUserId(request);
            UserInfo user = userMapper.getByUserId(userId);
            Double totalMoney = 0d;
            List<MyShopCart> carts = cartMapper.getSkuByCartIds(buyDto.getCartIds());
            for (MyShopCart cart:carts){
                BigDecimal num1 = new BigDecimal(totalMoney);
                BigDecimal singlePrice = new BigDecimal(null!=cart.getDiscountPrice()?cart.getDiscountPrice():cart.getOrginPrice());
                BigDecimal numCount = new BigDecimal(cart.getNumCount());
                totalMoney = num1.add(singlePrice.multiply(numCount)).doubleValue();
            }
            //余额支付先判断余额是否充足
            if (buyDto.getPayType()==3){
                BigDecimal balance = new BigDecimal(user.getBalance());
                BigDecimal num2 = new BigDecimal(totalMoney);
                if (balance.subtract(num2).doubleValue()<0){
                    if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                        return HttpResult.fail("Your balance is insufficient, please recharge");
                    }
                    return HttpResult.fail("您的餘額不足，請確認！");
                }
            }

            //创建订单号
            String code = CodeUtil.verifyCode(6);
            String today = DateUtil.format(new Date(), "yyyyMMdd");
            String orderNo = "sn".concat(today).concat(code);
            String agent = request.getHeader("agent");
            if (StringUtils.isNotEmpty(agent)&&agent.equals("app")){
                orderNo = "sp".concat(today).concat(code);
            }
            TbOrder order = new TbOrder();
            order.setOrderNo(orderNo);
            if (StringUtils.isNotEmpty(buyDto.getReceivingAddrId())) {
                ReceivingAddrInfo addrInfo = addrInfoMapper.getByReceivingAddrId(buyDto.getReceivingAddrId());
                order.setReceiverAddress(addrInfo.getReceivingAddress());
                order.setReceiverMobile(addrInfo.getContactPhone());
                order.setReceiver(addrInfo.getContact());
            }
            order.setUserId(userId);
            order.setBuyerNick(user.getNickName());
            order.setPayType(buyDto.getPayType());
            order.setOrderType(OrderType.PRODUCT.value());
            order.setActualPay(totalMoney);
            order.setTotalPay(totalMoney);
            order.setPayStatus(PayStatus.PAYING.value());

            for (MyShopCart cart:carts) {
                TbOrderDetail detail = new TbOrderDetail();
                detail.setOrderNo(orderNo);
                detail.setSkuId(cart.getSkuId());
                detail.setSkuName(cart.getSkuName());
                detail.setSkuSpecs(cart.getSkuSpecs());
                detail.setImage(cart.getSkuImgUrl());
                detail.setDeliveryWay(buyDto.getDeliveryWay());
                detail.setPrice(null != cart.getDiscountPrice() ? cart.getDiscountPrice() : cart.getOrginPrice());
                detail.setNumCount(cart.getNumCount());
                if (buyDto.getPayType()==3) {
                    detail.setIsConfirm(1);
                }
                ordeDetailMapper.insert(detail);
            }
            //余额支付直接扣款
            if (buyDto.getPayType()==3){
                BigDecimal num1 = new BigDecimal(user.getBalance());
                BigDecimal num2 = new BigDecimal(totalMoney);
                user.setBalance(num1.subtract(num2).doubleValue());
                userMapper.updateBalance(user);
                //主动触发回调
                order.setPayTime(new Date());
                order.setCloseTime(new Date());
                order.setEndTime(new Date());
                order.setPayStatus(PayStatus.COMPLETED.value());
                for (MyShopCart detail:carts) {
                    PdSku dbSku = pdSkuMapper.getBySkuId(detail.getSkuId());
                    String key="sku_" + detail.getSkuId();
                    //实物产品修改产品库存数
                    if (redisUtil.hasKey(key)&&ProductType.GOODS.value()==dbSku.getType()) {
                        String lock_key="sku_lock_"+detail.getSkuId();
                        RLock lock = redisson.getLock(lock_key);
                        //try catch 设计是为了防止在执行业务的时候出现异常导致redis锁一直无法释放
                        try {
                            lock.lock();
                            int count = Integer.parseInt(redisUtil.get(key).toString());
                            int stockCount = count-detail.getNumCount();
                            int saleCount = dbSku.getSaleStockCount()+detail.getNumCount();
                            if (saleCount>=dbSku.getLockStockCount()||0>=stockCount){
                                dbSku.setSaleStatus(SaleStatus.SELL_OUT.value());
                            }
                            dbSku.setSaleStockCount(saleCount);
                            redisUtil.set(key, stockCount);
                            dbSku.setStockCount(stockCount);
                            pdSkuMapper.updateStockCount(dbSku);
                        } catch (Throwable e) {
                            e.printStackTrace();
                        } finally {
                            lock.unlock();
                        }
                    }
                    //AI次数
                    if (ProductType.AI_TIMES.value()==dbSku.getType()) {
                        List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                        if (!CollectionUtils.isEmpty(attributeValues)){
                            String value = attributeValues.get(0).getAttributeValue();
                            Integer times = Integer.valueOf(value.replaceAll("[^0-9]",""))*detail.getNumCount();
                            user.setAiTimes(user.getAiTimes()+times);
                            userMapper.updateAiTimes(user);
                        }
                    }
                    //储存空间
                    if (ProductType.STORAGE.value()==dbSku.getType()) {
                        List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                        if (!CollectionUtils.isEmpty(attributeValues)){
                            String value = attributeValues.get(0).getAttributeValue();
                            Integer storage = Integer.valueOf(value.replaceAll("[^0-9]",""))*detail.getNumCount();

                            TbOrderVirtually orderStorage = new TbOrderVirtually();
                            orderStorage.setUserId(order.getUserId());
                            orderStorage.setOrderNo(orderNo);
                            orderStorage.setNumCount(detail.getNumCount());
                            orderStorage.setSkuId(detail.getSkuId());
                            orderStorage.setStorageOrTimes(storage);
                            orderStorage.setPurchaseTime(new Date());
                            orderStorage.setEffectiveTime(new Date());
                            if (value.contains("GB/年")){
                                orderStorage.setDateType(1);
                                orderStorage.setExpiredTime(DateUtils.add(new Date(),Calendar.YEAR,1));
                            }else if(value.contains("GB/月")){
                                orderStorage.setDateType(2);
                                orderStorage.setExpiredTime(DateUtils.add(new Date(),Calendar.MONTH,1));
                            }
                            orderVirtuallyMapper.insert(orderStorage);
                        }
                    }
                }
                for (String cartId:buyDto.getCartIds()) {
                    cartMapper.deleteById(cartId);
                }
            }else{
                cartMapper.setOrderNo(orderNo,buyDto.getCartIds());
            }
            orderMapper.initOrder(order);
            return new HttpResult(orderNo);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }


    @Override
    public HttpResult recharge(HttpServletRequest request, TbOrder order) {
        try {
            String userId = tokenUtil.getUserId(request);
            //创建订单号
            String code = CodeUtil.verifyCode(6);
            String today = DateUtil.format(new Date(), "yyyyMMdd");
            String orderNo = "sn".concat(today).concat(code);
            String agent = request.getHeader("agent");
            if (StringUtils.isNotEmpty(agent)&&agent.equals("app")){
                orderNo = "sp".concat(today).concat(code);
            }
            order.setPayStatus(PayStatus.PAYING.value());
            order.setOrderNo(orderNo);
            order.setUserId(userId);
            order.setOrderType(OrderType.RECHARGE.value());
            orderMapper.initOrder(order);
            return new HttpResult(orderNo);
        }catch (Exception e){
            e.printStackTrace();
            return HttpResult.fail("初始化充值失敗！");
        }
    }
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    @Override
    public void rechargeNotify(PayResult payResult) {
        try {
            String orderNo = payResult.getMerchant_reference();
            orderMapper.setSign(orderNo,payResult.getSign());

            TbOrder dbOrder = orderMapper.getByOrderNo(orderNo);
            dbOrder.setPayTime(new Date());
            dbOrder.setCloseTime(new Date());
            dbOrder.setEndTime(new Date());
            if (PaymentAsiaStatus.SUCCESS.value()!=payResult.getStatus()){
                dbOrder.setPayStatus(PayStatus.FAIL.value());
                if (payResult.getStatus()==0){
                    dbOrder.setFailReason("your order is pending for deposit");
                }else if(payResult.getStatus()==2){
                    dbOrder.setFailReason("your order's deposit is rejected");
                }
                orderMapper.updateOrder(dbOrder);
                return;
            }
//            if (dbOrder.getActualPay().doubleValue()!=payResult.getAmount().doubleValue()){
//                dbOrder.setPayStatus(PayStatus.FAIL.value());
//                dbOrder.setFailReason("订单金额应该与返回金额不一致");
//                orderMapper.updateOrder(dbOrder);
//                return;
//            }

            if (dbOrder.getOrderType()==OrderType.RECHARGE.value()) {
                UserInfo user = userMapper.getByUserId(dbOrder.getUserId());
                BigDecimal num1 = new BigDecimal(user.getBalance());
                BigDecimal num2 = new BigDecimal(dbOrder.getActualPay());
                user.setBalance(num1.add(num2).doubleValue());
                userMapper.updateBalance(user);
            }
            dbOrder.setPayStatus(PayStatus.COMPLETED.value());
            orderMapper.updateOrder(dbOrder);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException("充值回调失败"+e.getMessage());
        }
    }

//    @Override
//    public HttpResult rechargePage(HttpServletRequest request, ComposeQueryDto qto) {
//        Page page = qto.getPage();
//        page.initPagingData(RechargeRecord.class);
//        String userId = tokenUtil.getUserId(request);
//        List<RechargeRecord> list = rechargeRecordMapper.myRecharge(userId);
//        page.setResult(list);
//        return new HttpResult(page);
//    }


//    @Override
//    public void rechargeNotify(String rechargeId) {
//        try {
//            RechargeRecord rechargeRecord = rechargeRecordMapper.getByRechargeId(rechargeId);
//            UserInfo user = userMapper.getByUserId(rechargeRecord.getUserId());
//            BigDecimal num1 = new BigDecimal(user.getBalance());
//            BigDecimal num2 = new BigDecimal(rechargeRecord.getPrice());
//            user.setBalance(num1.add(num2).doubleValue());
//            userMapper.updateBalance(user);
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//    }
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    @Override
    public void productNotify(PayResult payResult,Boolean isCart) {
        try {
            String orderNo = payResult.getMerchant_reference();
            orderMapper.setSign(orderNo,payResult.getSign());
            TbOrder order = orderMapper.getByOrderNo(orderNo);
            order.setPayTime(new Date());
            order.setCloseTime(new Date());
            order.setEndTime(new Date());
            if (PaymentAsiaStatus.SUCCESS.value()!=payResult.getStatus()){
                order.setPayStatus(PayStatus.FAIL.value());
                if (payResult.getStatus()==0){
                    order.setFailReason("your order is pending for deposit");
                }else if(payResult.getStatus()==2){
                    order.setFailReason("your order's deposit is rejected");
                }
                orderMapper.updateOrder(order);
                return;
            }
//            if (payResult.getAmount()<order.getActualPay()){
//                order.setPayStatus(PayStatus.FAIL.value());
//                order.setFailReason("订单金额应该与返回金额不一致");
//                orderMapper.updateOrder(order);
//                return;
//            }
            order.setPayStatus(PayStatus.SUCCESS.value());

            List<TbOrderDetail> orderDetails = ordeDetailMapper.getByOrderNo(orderNo);
            if (!CollectionUtils.isEmpty(orderDetails)){
                boolean hasGoods = false;
                for (TbOrderDetail detail :orderDetails) {
                    PdSku dbSku = pdSkuMapper.getBySkuId(detail.getSkuId());
                    String key="sku_" + detail.getSkuId();
                    //实物产品修改产品库存数
                    if (redisUtil.hasKey(key)&&ProductType.GOODS.value()==dbSku.getType()) {
                        hasGoods = true;
                        String lock_key="sku_lock_"+detail.getSkuId();
                        RLock lock = redisson.getLock(lock_key);
                        //try catch 设计是为了防止在执行业务的时候出现异常导致redis锁一直无法释放
                        try {
                            lock.lock();
                            int count = Integer.parseInt(redisUtil.get(key).toString());
                            int stockCount = count-detail.getNumCount();
                            int saleCount = dbSku.getSaleStockCount()+detail.getNumCount();
                            if (saleCount>=dbSku.getLockStockCount()||0>=stockCount){
                                dbSku.setSaleStatus(SaleStatus.SELL_OUT.value());
                            }
                            dbSku.setSaleStockCount(saleCount);
                            redisUtil.set(key, stockCount);
                            dbSku.setStockCount(stockCount);
                            pdSkuMapper.updateStockCount(dbSku);
                        } catch (Throwable e) {
                            e.printStackTrace();
                        } finally {
                            lock.unlock();
                        }
                    }
                    //AI次数
                    if (ProductType.AI_TIMES.value()==dbSku.getType()||ProductType.FACE_TIMES.value()==dbSku.getType()) {
                        List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                        if (!CollectionUtils.isEmpty(attributeValues)){
                            String value = attributeValues.get(0).getAttributeValue();
                            Integer times = Integer.valueOf(value.replaceAll("[^0-9]",""))*detail.getNumCount();
                            TbOrderVirtually orderStorage = new TbOrderVirtually();
                            orderStorage.setUserId(order.getUserId());
                            orderStorage.setOrderNo(orderNo);
                            orderStorage.setVirtuallyType(ProductType.AI_TIMES.value());
                            if (ProductType.FACE_TIMES.value()==dbSku.getType()) {
                                orderStorage.setVirtuallyType(ProductType.FACE_TIMES.value());
                            }
                            orderStorage.setNumCount(detail.getNumCount());
                            orderStorage.setSkuId(detail.getSkuId());
                            orderStorage.setStorageOrTimes(times);
                            orderStorage.setPurchaseTime(new Date());
                            orderStorage.setEffectiveTime(new Date());
                            orderVirtuallyMapper.insert(orderStorage);
                        }
                    }
                    //储存空间
                    if (ProductType.STORAGE.value()==dbSku.getType()) {
                        List<PdAttributeValue> attributeValues = attributeValueMapper.getBySkuId(detail.getSkuId());
                        if (!CollectionUtils.isEmpty(attributeValues)){
                            String value = attributeValues.get(0).getAttributeValue();
                            Integer storage = Integer.valueOf(value.replaceAll("[^0-9]",""))*detail.getNumCount();

                            TbOrderVirtually orderStorage = new TbOrderVirtually();
                            orderStorage.setUserId(order.getUserId());
                            orderStorage.setOrderNo(orderNo);
                            orderStorage.setNumCount(detail.getNumCount());
                            orderStorage.setSkuId(detail.getSkuId());
                            orderStorage.setStorageOrTimes(storage);
                            orderStorage.setPurchaseTime(new Date());
                            orderStorage.setEffectiveTime(new Date());
                            if (value.contains("GB/年")){
                                orderStorage.setDateType(1);
                                orderStorage.setExpiredTime(DateUtils.add(new Date(),Calendar.YEAR,1));
                            }else if(value.contains("GB/月")){
                                orderStorage.setDateType(2);
                                orderStorage.setExpiredTime(DateUtils.add(new Date(),Calendar.MONTH,1));
                            }
                            orderVirtuallyMapper.insert(orderStorage);
                        }
                    }
                    orderMapper.confirmOrder(orderNo, detail.getSkuId(), 1);
                }
                if (!hasGoods) {
                    order.setPayStatus(PayStatus.COMPLETED.value());
                }
            }
            if (isCart){//清空购物车
                cartMapper.deleteByOrderNo(orderNo);
            }
            orderMapper.updateOrder(order);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException("产品购买回调失败"+e.getMessage());
        }
    }
    @Override
    public HttpResult getVipPrice(HttpServletRequest request, VipBuyDto vip) {
        String userId = tokenUtil.getUserId(request);
        VipProperties dbVip = vipPropertiesMapper.getByServiceCode(vip.getServiceCode());

        Double price = 0d;
        UserVip currentVip = userVipMapper.getCurrentVip(userId);
        if (null==currentVip||currentVip.getIsFree()==1){//不存在计算差价，直接返回
            price = dbVip.getCurrentPrice()==null?dbVip.getPrice():dbVip.getCurrentPrice();
        }else{
            BigDecimal newVipPrice = new BigDecimal(null!=dbVip.getCurrentPrice()?dbVip.getCurrentPrice():dbVip.getPrice());
            BigDecimal oldVipPrice = new BigDecimal(null!=currentVip.getCurrentPrice()?currentVip.getCurrentPrice():currentVip.getPrice());
            BigDecimal oldTotalDay = new BigDecimal(currentVip.getTotalDay());
            //原vip日均价格
            BigDecimal oldAvgPrice = oldVipPrice.divide(oldTotalDay ,2, RoundingMode.HALF_UP);
            int usedDay = DateUtils.getDatePoordDay(new Date(), currentVip.getPurchaseTime())+1;
            BigDecimal lastDay = new BigDecimal((currentVip.getTotalDay()-usedDay));
            //剩余未使用天数折算的价格
            BigDecimal lastPrice = oldAvgPrice.multiply(lastDay);
            //应付价格=新vip价格-剩余未使用天数折算的价格
            price = newVipPrice.subtract(lastPrice).doubleValue();
        }
        return new HttpResult(price);
    }

//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    @Override
    public HttpResult vip(HttpServletRequest request, VipBuyDto vip) {
        try {
            String language = request.getHeader("language");
            String userId = tokenUtil.getUserId(request);
            VipProperties dbVip = vipPropertiesMapper.getByServiceCode(vip.getServiceCode());

            UserVip currentVip = userVipMapper.getCurrentVip(userId);
            if (null!=currentVip&&currentVip.getIsFree()!=1){//不存在计算差价，直接返回
                //判断权重是否是升级
                if(dbVip.getServiceCode().equalsIgnoreCase(currentVip.getServiceCode())){
                    if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                        return HttpResult.fail("You currently have this type of vip and cannot make duplicate purchases");
                    }
                    return HttpResult.fail("您當前已擁有該類型會員，不可重複購買！");
                }
                //判断权重是否是升级
                if(dbVip.getWeight()<currentVip.getWeight()){
                    if(StringUtils.isNotEmpty(language)&&language.equals("en")){
                        return HttpResult.fail("You currently have a vip with higher privileges and cannot downgrade the purchase");
                    }
                    return HttpResult.fail("您當前有更高權限的會員，不可降級購買！");
                }
            }
            TbOrder order = new TbOrder();
            //创建订单号
            String code = CodeUtil.verifyCode(6);
            String today = DateUtil.format(new Date(), "yyyyMMdd");
            String orderNo = "sn".concat(today).concat(code);
            String agent = request.getHeader("agent");
            if (StringUtils.isNotEmpty(agent)&&agent.equals("app")){
                orderNo = "sp".concat(today).concat(code);
            }
            order.setOrderNo(orderNo);
            order.setPayStatus(PayStatus.PAYING.value());
            order.setUserId(userId);
            order.setOrderType(OrderType.VIP.value());
            order.setActualPay(dbVip.getCurrentPrice()==null?dbVip.getPrice():dbVip.getCurrentPrice());
            order.setTotalPay(dbVip.getCurrentPrice()==null?dbVip.getPrice():dbVip.getCurrentPrice());
            order.setPayStatus(PayStatus.PAYING.value());
            order.setPayType(vip.getPayType());

            //初始创建会员购买
            UserVip userVip = new UserVip();
            userVip.setCurrentPrice(dbVip.getCurrentPrice());
            userVip.setPrice(dbVip.getPrice());
            userVip.setOrderNo(orderNo);
            userVip.setServiceCode(dbVip.getServiceCode());
            userVip.setServiceName(dbVip.getServiceName());
            userVip.setIsFacialRecognition(dbVip.getIsFacialRecognition());
            userVip.setIsCompression(dbVip.getIsCompression());
            userVip.setServiceDate(dbVip.getServiceDate());
            userVip.setDateType(dbVip.getDateType());
            if (dbVip.getDateType()==1){
                userVip.setTotalDay(365*dbVip.getServiceDate());
            }else if (dbVip.getDateType()==2){
                userVip.setTotalDay(30*dbVip.getServiceDate());
            }else if (dbVip.getDateType()==5){
                userVip.setTotalDay(dbVip.getServiceDate());
            }
            userVip.setDownloadTypes(dbVip.getDownloadTypes());
            userVip.setIsFtp(dbVip.getIsFtp());
            userVip.setIsFree(dbVip.getIsFree());
            userVip.setIsOnline(dbVip.getIsOnline());
            userVip.setIsSecretVisit(dbVip.getIsSecretVisit());
            userVip.setIsHighSecret(dbVip.getIsHighSecret());
            userVip.setIsPoster(dbVip.getIsPoster());
            userVip.setAiTimes(dbVip.getAiTimes());
            userVip.setSurplusAiTimes(dbVip.getAiTimes());
            userVip.setIsVideo(dbVip.getIsVideo());
            userVip.setIsLogo(dbVip.getIsLogo());
            userVip.setStorage(dbVip.getStorage());
            userVip.setWeight(dbVip.getWeight());
            userVip.setUserId(userId);
            userVip.setStatus(VipStatus.INIT.value());
            userVip.setPurchaseTime(new Date());

            //余额支付直接扣款
            if (vip.getPayType() == PayType.BALANCE.value()) {
                UserInfo user = userMapper.getByUserId(userId);
                BigDecimal num1 = new BigDecimal(user.getBalance());
                Double price = 0d;
                if (null==currentVip||currentVip.getIsFree()==1){//不存在计算差价，直接返回
                    price = dbVip.getCurrentPrice()==null?dbVip.getPrice():dbVip.getCurrentPrice();
                }else{
                    BigDecimal newVipPrice = new BigDecimal(null!=dbVip.getCurrentPrice()?dbVip.getCurrentPrice():dbVip.getPrice());
                    BigDecimal oldVipPrice = new BigDecimal(null!=currentVip.getCurrentPrice()?currentVip.getCurrentPrice():currentVip.getPrice());
                    BigDecimal oldTotalDay = new BigDecimal(currentVip.getTotalDay());
                    //原vip日均价格
                    BigDecimal oldAvgPrice = oldVipPrice.divide(oldTotalDay ,2, RoundingMode.HALF_UP);
                    int usedDay = DateUtils.getDatePoordDay(new Date(), currentVip.getPurchaseTime())+1;
                    BigDecimal lastDay = new BigDecimal((currentVip.getTotalDay()-usedDay));
                    //剩余未使用天数折算的价格
                    BigDecimal lastPrice = oldAvgPrice.multiply(lastDay);
                    //应付价格=新vip价格-剩余未使用天数折算的价格
                    price = newVipPrice.subtract(lastPrice).doubleValue();
                }

                BigDecimal num2 = new BigDecimal(price);
                user.setBalance(num1.subtract(num2).doubleValue());
                userMapper.updateBalance(user);

                //主动触发回调
                order.setPayTime(new Date());
                order.setCloseTime(new Date());
                order.setEndTime(new Date());
                order.setPayStatus(PayStatus.COMPLETED.value());
                orderMapper.updateOrder(order);

                //将之前会员改为已使用
                if (null!=currentVip) {
                    currentVip.setStatus(VipStatus.USED.value());
                    userVipMapper.updateVip(currentVip);
                }
                //当前会员改为使用中
                userVip.setExpiredTime(DateUtils.add(new Date(), userVip.getDateType(),userVip.getServiceDate()));
                userVip.setEffectiveTime(new Date());
                userVip.setStatus(VipStatus.IN_EFFECT.value());

                if(user.getStatus()!=UserStatus.NORMAL.value()){
                    userMapper.updateStatus(order.getUserId(),UserStatus.NORMAL.value());
                    photoMapper.unlockUserPhoto(order.getUserId());
                    if(user.getStatus()==UserStatus.SECOND_LEVEL_LOCKED.value()){
                        thawingPhoto(order.getUserId());
                    }
                }
            }
            userVipMapper.insert(userVip);
            orderMapper.initOrder(order);
            return new HttpResult(orderNo);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }




    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    @Override
    public void vipNotify(PayResult payResult) {
        try {
            String orderNo = payResult.getMerchant_reference();
            orderMapper.setSign(orderNo,payResult.getSign());
            TbOrder order = orderMapper.getByOrderNo(orderNo);
            order.setPayTime(new Date());
            order.setCloseTime(new Date());
            order.setEndTime(new Date());
            if (PaymentAsiaStatus.SUCCESS.value()!=payResult.getStatus()){
                order.setPayStatus(PayStatus.FAIL.value());
                if (payResult.getStatus()==0){
                    order.setFailReason("your order is pending for deposit");
                }else if(payResult.getStatus()==2){
                    order.setFailReason("your order's deposit is rejected");
                }
                orderMapper.updateOrder(order);
                return;
            }
//            if (payResult.getAmount()<order.getActualPay()){
//                order.setPayStatus(PayStatus.FAIL.value());
//                order.setFailReason("订单金额应该与返回金额不一致");
//                orderMapper.updateOrder(order);
//                return;
//            }
            order.setPayStatus(PayStatus.COMPLETED.value());
            orderMapper.updateOrder(order);
            //将之前会员改为已使用
            UserVip currentVip = userVipMapper.getCurrentVip(order.getUserId());
            if (null!=currentVip) {
                currentVip.setStatus(VipStatus.USED.value());
                userVipMapper.updateVip(currentVip);
            }
            //当前会员改为使用中
            UserVip buyVip = userVipMapper.getByOrderNo(orderNo);
            buyVip.setExpiredTime(DateUtils.add(new Date(), buyVip.getDateType(),buyVip.getServiceDate()));
            buyVip.setEffectiveTime(new Date());
            buyVip.setStatus(VipStatus.IN_EFFECT.value());
            userVipMapper.updateVip(buyVip);
            //如果是有ftp权限，恢复ftp账号
            if (buyVip.getIsFtp()==1){
                int count = ftpMapper.updateStatus(order.getUserId(),0);
                if (count>0){
                    userSevice.resetFtpFile();
                }
            }

            UserInfo user = userMapper.getByUserId(order.getUserId());
            if(user.getStatus()!=UserStatus.NORMAL.value()){
                userMapper.updateStatus(order.getUserId(),UserStatus.NORMAL.value());
                photoMapper.unlockUserPhoto(order.getUserId());
                if(user.getStatus()==UserStatus.SECOND_LEVEL_LOCKED.value()){
                    thawingPhoto(order.getUserId());
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException("vip购买回调失败"+e.getMessage());
        }
    }

    @Async
    public void thawingPhoto(String userId){
        List<PictureInfo> pictureList = pictureMapper.getMostPicByUserId(userId, OssStorageClassLevel.ColdArchive.value());
        for (PictureInfo picture:pictureList){
            //解冻冷归档文件
            if (StorageClass.ColdArchive.toString().equalsIgnoreCase(picture.getOssStorageClass())){
                AliOssUtil.thawingColdFile(picture.getPictureUrl());
                picture.setStatus(PictureStatus.THAWING.value());
                pictureMapper.updatePicture(picture);
            }
            //解冻深度冷归档文件
            if (StorageClass.DeepColdArchive.toString().equalsIgnoreCase(picture.getOssStorageClass())){
                AliOssUtil.thawingDeepColdFile(picture.getPictureUrl());
                picture.setStatus(PictureStatus.THAWING.value());
                pictureMapper.updatePicture(picture);
            }
        }
    }
}
